package com.eric.study.jobflow.job;

import com.eric.study.jobflow.function.Fun1;
import com.eric.study.jobflow.function.Fun2;
import com.eric.study.jobflow.function.Predicate1;
import com.eric.study.jobflow.function.Predicate2;
import lombok.Getter;
import lombok.Setter;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p> JobNode.
 *
 * <p>
 * change history:
 *
 * <pre>
 * date         defect       person          comments
 * --------------------------------------------------------------------------------
 * 2023/8/31    ********     Eric    create file.
 * </pre>
 *
 * @param <P> 作业节点执行的命令类型限制
 * @param <R> 作业节点执行结果类型限制
 * @author Eric
 * @date 2023/8/31 10:54
 * @copyright 2023, FA Software (Shanghai) Co., Ltd. All Rights Reserved.
 * @since 1.0.0
 */
@Getter
public class JobNode<P, R> {

    @Setter
    private String name;

    private final int number;

    @Setter
    private P command;

    @Setter
    private R result;

    private final AtomicInteger inDegree = new AtomicInteger(0);

    private final AtomicInteger outDegree = new AtomicInteger(0);

    @Getter
    private final Set<JobNode<?, ?>> nextNodes;

    @Getter
    private final Set<JobNode<?, ?>> previousNodes;

    /**
     * 参数计算函数
     */
    @Setter
    private Fun1<?, ?> paramFun1;

    /**
     * 参数计算函数
     */
    @Setter
    private Fun2<?, ?, ?> paramFun2;


    /**
     * 请求参数构建计算依赖的节点
     */
    @Getter
    private final Queue<JobNode<?, ?>> paramDependNodes;

    /**
     * 执行条件计算
     */
    @Setter
    private Predicate1<?> condition1;

    /**
     * 执行条件计算
     */
    @Setter
    private Predicate2<?, ?> condition2;

    /**
     * condition 节点计算依赖的节点
     */
    private final Queue<JobNode<?, ?>> conditionDependNodes;

    public JobNode(int number, String name) {
        this.name = name;
        this.number = number;
        this.nextNodes = new HashSet<>();
        this.previousNodes = new HashSet<>();

        //
        this.paramDependNodes = new LinkedList<>();
        this.conditionDependNodes = new LinkedList<>();
    }

    public int inDegree() {
        return this.inDegree.get();
    }

    public void inDegreeIncrement() {
        inDegree.incrementAndGet();
    }

    public void inDegreeDecrement() {
        inDegree.decrementAndGet();
    }

    public int outDegree() {
        return this.outDegree.get();
    }

    public void outDegreeIncrement() {
        outDegree.incrementAndGet();
    }

    public void outDegreeDecrement() {
        outDegree.decrementAndGet();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        JobNode<?, ?> jobNode = (JobNode<?, ?>) o;
        return number == jobNode.number && Objects.equals(name, jobNode.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, number);
    }

    @Override
    public String toString() {
        return "JobNode{" +
                "name='" + name + '\'' +
                ", number=" + number +
                '}';
    }
}
